home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch03 / morph.c < prev    next >
C/C++ Source or Header  |  1993-06-11  |  9KB  |  287 lines

  1. /****************************************************************
  2. * FILE:    morph.c
  3. * DESC:    Create a metamorphosing sequence between two given
  4. *        images. This program lets you specify two files to
  5. *        morph, then prompts you for control lines. It uses
  6. *        the lines to warp the underlying images a step at
  7. *        a time, combine them, and optionally save them as
  8. *        numbered PCX files.
  9. * HISTORY:    Created     1/13/1993
  10. * LAST CHANGED:  5/ 6/1993
  11. *    Copyright (c) 1993 by Scott Anderson
  12. *
  13. ****************************************************************/
  14.  
  15. /* ----------------------INCLUDES----------------------------- */
  16.  
  17. #include <conio.h>
  18. #include <stdio.h>
  19. #include <io.h>
  20. #include <math.h>
  21. #include <graph.h>
  22. #include <malloc.h>
  23. #include <memory.h>
  24. #include <string.h>
  25.  
  26. #include "define.h"
  27.  
  28. /* ----------------------DEFINES------------------------------ */
  29.  
  30. #define MORPH_TWEENS    1
  31.  
  32. /* ----------------------PROTOTYPES--------------------------- */
  33.  
  34. int        tweenMorph(PICTURE *src, PICTURE *dst);
  35.  
  36. /* ----------------------EXTERNALS---------------------------- */
  37.  
  38. /**** color routines ****/
  39. extern int    closestColor(int r, int g, int b, PALETTE *palPtr);
  40. extern void    collapseColors(PALETTE *palPtr);
  41.  
  42. /**** line routines ****/
  43. extern int    setLength(LINE *line);
  44. extern int    sumLines(PICTURE *picture, COLOR *color,
  45.                     LINE *origline, POINT *warp, LINE *warpline);
  46.  
  47. /**** io routines ****/
  48. extern LINE_LIST    *loadLines(char *filename, char *extension);
  49. extern void          saveLines(char *filename,
  50.                         LINE_LIST *lineList, char *extension);
  51.  
  52. /***** variables used to compute intermediate images ****/
  53.  
  54. /* number of colors in tweened image before reduction*/
  55. extern int     Ncolors;
  56.  
  57. /* r, g, b frequency counter array */
  58. extern unsigned int far Freq[MAX_COMP][MAX_COMP][MAX_COMP];
  59.  
  60. /* tweened images red, grn, and blu components*/
  61. extern unsigned char far Red[MAX_WIDE][MAX_TALL];
  62. extern unsigned char far Grn[MAX_WIDE][MAX_TALL];
  63. extern unsigned char far Blu[MAX_WIDE][MAX_TALL];
  64.  
  65. extern PALETTE TweenPal;            /* resulting palette */
  66.  
  67. /**** other variables ****/ 
  68. extern char        *OutFilename;
  69. /* set from last picture loaded */
  70. extern int        Xmin, Ymin, Xmax, Ymax;
  71. /* ID of palette currently being displayed */
  72. extern int         CurrentPal;
  73.  
  74. /* ----------------------GLOBAL DATA-------------------------- */
  75.  
  76. PICTURE *Src;        /* source & destination picture pointers */
  77. PICTURE *Dst;
  78.  
  79. LINE     SrcLine[MAX_LINES];
  80. LINE     DstLine[MAX_LINES];
  81.  
  82. int        Tweens;
  83. int        NumLines;
  84.  
  85. /*****************************************************************
  86. * FUNC: main (int argc, char *argv[])
  87. * DESC: Read in a filename to load
  88. *****************************************************************/
  89.  
  90. main (int argc, char *argv[])
  91. {
  92.     int        segment;
  93.     LINE_LIST *lineSrcList;
  94.     LINE_LIST *lineDstList;
  95.     char    answer;
  96.  
  97.     /* load the pcx file if one is given */
  98.     if ((3 > argc) || (argc > 5)) {
  99.         printf("Usage: morph <source> <dest> [<steps> [<output>]]\n\n");
  100.         printf("Where: <source> is the source PCX filename\n");
  101.         printf("       <dest>     is the destination filename\n");
  102.         printf("       <steps>  is the optional sequence size\n");
  103.         printf("                (the max is %d, the default is %d)\n",
  104.                                 MAX_TWEENS, MORPH_TWEENS+2);
  105.         printf("       <output> is the optional output filename\n");
  106.         printf("                (defaults to no output)\n\n");
  107.         printf("Note:  The output filename can be at most %d characters long.\n",
  108.                                 MAX_NAME_SIZE);
  109.         printf("       The PCX extension is added automatically, so don't\n");
  110.         printf("       include it in the filename.\n");
  111.         printf("       Morph only accepts PCX files with %d X %d resolution\n",
  112.                                 MAX_WIDE, MAX_TALL);
  113.         printf("       and %d colors.\n", COLORS);
  114.         exit(0);
  115.     }
  116.     if (argc > 3) {
  117.         /* subtract two from the series count to get the tweens
  118.          * since the starting and ending frame are included. */
  119.         Tweens = clip (atoi(argv[3]) - 2, 1, MAX_TWEENS);
  120.         if (argc > 4)
  121.             OutFilename = argv[4];
  122.     }
  123.     else
  124.         Tweens = MORPH_TWEENS;
  125.     
  126.     printf("Loading the file %s\n", argv[1]);
  127.     Src = loadPicture(argv[1]);
  128.     if (Src == NULL)
  129.         quit(MEMORY_ERR, "");
  130.     
  131.     printf("Loading the file %s\n", argv[2]);
  132.     Dst = loadPicture(argv[2]);
  133.     if (Dst == NULL)
  134.         quit(MEMORY_ERR, "");
  135.     lineSrcList = loadLines(argv[1], EXT_LINE1);
  136.     if (lineSrcList->number != 0) {
  137.         if (lineAsk(argv[1]) == 'N')
  138.             createLines(Src, lineSrcList);
  139.         else
  140.             editLines(Src, lineSrcList);
  141.     }
  142.     else
  143.         createLines(Src, lineSrcList);
  144.     
  145.     TargFlag = 1;    /* For the screen intro message */
  146.     NumLines = lineSrcList->number;
  147.     if (NumLines) {
  148.         lineDstList = loadLines(argv[2], EXT_LINE1);
  149.             /* inconsistent warp target*/
  150.         if (lineDstList->number !=  NumLines)
  151.             lineDstList->number = 0;
  152.         if (lineDstList->number) {    /* ask what he wants to do */
  153.             if (lineAsk(argv[2]) == 'N')
  154.                 lineDstList->number = 0;
  155.         }
  156.         if (lineDstList->number == 0) {    /* create a warp target */
  157.             /* copy the source lines */
  158.             lineDstList->number = NumLines;
  159.             for (segment = 0; segment < NumLines; segment++) 
  160.                 lineDstList->line[segment]
  161.                                 = lineSrcList->line[segment];
  162.         }
  163.  
  164.         editLines(Dst, lineDstList);
  165.         saveLines(argv[1], lineSrcList, EXT_LINE1);
  166.         saveLines(argv[2], lineDstList, EXT_LINE1);
  167.         beep();
  168.         for (segment = 0; segment < NumLines; segment++) {
  169.             DstLine[segment].p[0]=lineDstList->line[segment].p[0];
  170.             DstLine[segment].p[1]=lineDstList->line[segment].p[1];
  171.             setLength(&DstLine[segment]);
  172.             SrcLine[segment].p[0]=lineSrcList->line[segment].p[0];
  173.             SrcLine[segment].p[1]=lineSrcList->line[segment].p[1];
  174.             setLength(&SrcLine[segment]);
  175.         }
  176.     }
  177.  
  178.     tweenMorph(Src, Dst);
  179.     setTextMode();
  180. }
  181.  
  182. /*****************************************************************
  183. * FUNC: int    tweenMorph(PICTURE *src, PICTURE *dst)
  184. * DESC: calculate a pixel to plot, from the warping function
  185. *****************************************************************/
  186.  
  187. #define TOTAL_WEIGHT        (100)    /* Good for up to 99 tweens */
  188.  
  189. tweenMorph(PICTURE *src, PICTURE *dst)
  190. {
  191.     int color;
  192.     POINT warp;
  193.     int    x,y;
  194.     COLOR scolor, dcolor;
  195.     LINE warpLine[MAX_LINES];
  196.     int t, i, p;
  197.     int r, g, b;
  198.     unsigned int srcweight, srcpaletteindex;
  199.     unsigned int dstweight, dstpaletteindex;
  200.  
  201.     displayPicture(src);
  202.     saveScreen(&src->pal);
  203.  
  204.     /* src is on screen, now tween to the target */
  205.     for (t = 1; t <= Tweens; t++) {
  206.         /* Tween the lines used to warp the images */
  207.         for (i = 0; i < NumLines; i++) {
  208.             for (p = 0; p < 2; p++) {
  209.                 warpLine[i].p[p].x = SrcLine[i].p[p].x +
  210.                     ((DstLine[i].p[p].x - SrcLine[i].p[p].x) * t)
  211.                     /(Tweens+1);
  212.                 warpLine[i].p[p].y = SrcLine[i].p[p].y +
  213.                     ((DstLine[i].p[p].y - SrcLine[i].p[p].y) * t)
  214.                     /(Tweens+1);
  215.             }
  216.             setLength(&warpLine[i]);
  217.         }
  218.  
  219.         dstweight = t * TOTAL_WEIGHT / (Tweens+1);
  220.         srcweight = TOTAL_WEIGHT - dstweight;
  221.  
  222.         /* Zero out the buffers */
  223.         initFreq();
  224.         /* set background to black */
  225.         _fmemset(Red, 0, sizeof Red);
  226.         _fmemset(Grn, 0, sizeof Grn);
  227.         _fmemset(Blu, 0, sizeof Blu);
  228.  
  229.         /* Go through the screen and get warped source pixels */
  230.         for (warp.y = Ymin; warp.y <= Ymax; warp.y++)    {
  231.             if (quitCheck())
  232.                 quit(0, "");
  233.             for (warp.x = Xmin; warp.x <= Xmax; warp.x++)    {    
  234.                 sumLines(src, &scolor, SrcLine, &warp, warpLine);
  235.                 sumLines(dst, &dcolor, DstLine, &warp, warpLine);
  236.                 r = (scolor.r * srcweight +    dcolor.r * dstweight)
  237.                             / TOTAL_WEIGHT;
  238.                 g = (scolor.g * srcweight +    dcolor.g * dstweight)
  239.                             / TOTAL_WEIGHT;
  240.                 b = (scolor.b * srcweight +    dcolor.b * dstweight)
  241.                             / TOTAL_WEIGHT;
  242.                 if (Freq[r][g][b] == 0)        /* A new color */
  243.                     Ncolors++;
  244.                 /* Keep it to one byte */
  245.                 if (Freq[r][g][b] < MAX_FREQ)
  246.                     Freq[r][g][b]++;
  247.                 /* put RGB components into temporary buffer */
  248.                 Red[warp.x][warp.y] = r;
  249.                 Grn[warp.x][warp.y] = g;
  250.                 Blu[warp.x][warp.y] = b;
  251.             }
  252.         }
  253.         collapseColors(&TweenPal);
  254.         setPalette(&TweenPal);
  255.  
  256.         for (y = Ymin; y <= Ymax; y++)    {
  257.             if (quitCheck())
  258.                 quit(0, "");
  259.             for (x = Xmin; x <= Xmax; x++)    {
  260.                 color = closestColor(    Red[x][y],
  261.                                         Grn[x][y],
  262.                                         Blu[x][y],
  263.                                         &TweenPal);
  264.                 _setcolor (color);
  265.                 _setpixel (x, y);
  266.             }
  267.         }
  268.         /* no output file name on command line */
  269.         if (!OutFilename) {
  270.             beep();
  271.             waitForKey();    /* so pause to enjoy the pictures */
  272.         }
  273.         else
  274.             saveScreen(&TweenPal);
  275.     }
  276.     if (OutFilename) {    /* save the last pic in this series */
  277.         CurrentPal = 0;         /* force a new palette */
  278.         displayPicture(dst);
  279.         saveScreen(&dst->pal);
  280.     }
  281. }
  282.  
  283.